package com.woniuxy.kaer.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniuxy.kaer.commons.util.MD5Util;
import com.woniuxy.kaer.commons.util.OSSUtil;
import com.woniuxy.kaer.commons.util.Result;
import com.woniuxy.kaer.commons.util.SMSUtil;
import com.woniuxy.kaer.redis.util.RedisKey;
import com.woniuxy.kaer.user.dto.UserInfoDTO;
import com.woniuxy.kaer.user.form.SelectAddressForm;
import com.woniuxy.kaer.user.mapper.PointsLogMapper;
import com.woniuxy.kaer.user.model.PointsLog;
import com.woniuxy.kaer.user.model.UserInfo;
import com.woniuxy.kaer.user.mapper.UserInfoMapper;
import com.woniuxy.kaer.user.param.*;
import com.woniuxy.kaer.user.service.PointsLogService;
import com.woniuxy.kaer.user.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author sun
 * @since 2025年02月17日
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private SMSUtil smsUtil;
    @Resource
    private OSSUtil ossUtil;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private PointsLogMapper pointsLogMapper;
    @Resource
    private PointsLogService pointsLogService;


    @Override
    public void register(RegisterParam param) throws Exception {
        RLock lock1 = redissonClient.getFairLock(RedisKey.LOCK_ACCOUNT_BUSS(param.getAccount(), "register"));
        RLock lock2=redissonClient.getFairLock(RedisKey.LOCK_MOBILE_BUSS(param.getMobile(),"register"));
        RLock lock = redissonClient.getMultiLock(lock1, lock2);
        try {
            lock.lock();

            QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("account", param.getAccount());
            queryWrapper.or();
            queryWrapper.eq("mobile", param.getMobile());
            UserInfo userInfo1 = userInfoMapper.selectOne(queryWrapper);
            if (userInfo1 != null) {
                throw new Exception("账号或手机号已存在");
            }
            UserInfo userInfo = new UserInfo();
            userInfo.setPassword(MD5Util.md5(param.getPassword(), param.getAccount()));
            userInfo.setMobile(param.getMobile());
            userInfo.setAccount(param.getAccount());
            userInfo.setPoint(0);
            userInfo.setUserName(param.getUserName());
            userInfo.setIdCard(param.getIdCard());
            userInfo.setEmail(param.getEmail());
            userInfo.setQqOpenId(param.getQqOpenId());
            userInfoMapper.insert(userInfo);
        } finally {
            lock.unlock();
        }
        //删除注册验证码
        stringRedisTemplate.delete(RedisKey.REGISTER_USER_CODE_KEY(param.getMobile()));
    }

    @Override
    public UserInfoDTO userNameLogin(UserInfoLoginParam param) throws Exception {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account", param.getAccount());
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if (userInfo == null) {
            throw new Exception("用户不存在");
        }
        if (!MD5Util.md5(param.getPassword(), param.getAccount()).equals(userInfo.getPassword())) {
            throw new Exception("密码错误");
        }
        UserInfoDTO userInfoDTO = BeanUtil.toBean(userInfo, UserInfoDTO.class);
        return userInfoDTO;
    }

    @Override
    public void uploadHeader(UpLoadHeaderParam param) throws Exception {
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        //判断用户是否存在
        if (userInfo == null) {
            throw new Exception("用户不存在");
        }
        //文件上传阿里云OSS
        String originalFilename = param.getUserHeaderImage().getOriginalFilename();
        //获取文件后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        //雪花算法生成唯一文件名
        Snowflake snowflake = new Snowflake(1, 1);
        String fileName = snowflake.nextId() + suffix;
        //上传文件到OSS
        ossUtil.uploadFile(param.getUserHeaderImage().getInputStream(), fileName, "guojiandong");
        UserInfo userInfo1 = BeanUtil.toBean(param, UserInfo.class);
        userInfo1.setHeadPath(fileName);
        userInfoMapper.updateById(userInfo1);

    }

    @Override
    public void changePassword(Integer userId, String newPassword) throws Exception {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo == null) {
            throw new Exception("用户不存在");
        }
        String password = MD5Util.md5(newPassword, userInfo.getAccount());
        if (password.equals(userInfo.getPassword())) {
            throw new Exception("新密码不能与旧密码相同");
        }
        userInfo.setPassword(password);
        userInfoMapper.updateById(userInfo);
    }

    @Override
    public UserInfoDTO selectSelf(Integer userId) throws Exception {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        System.out.println("userInfo: " + userInfo);
        UserInfoDTO userInfoDTO = new UserInfoDTO();
        userInfoDTO.setUserId(userInfo.getUserId());
        userInfoDTO.setUserName(userInfo.getUserName());
        userInfoDTO.setHeadPath(userInfo.getHeadPath());
        userInfoDTO.setPoint(userInfo.getPoint());
        userInfoDTO.setMobile(userInfo.getMobile());
        userInfoDTO.setAccount(userInfo.getAccount());
        userInfoDTO.setEmail(userInfo.getEmail());
        userInfoDTO.setQqOpenId(userInfo.getQqOpenId());
        userInfoDTO.setIdCard(userInfo.getIdCard());
        return userInfoDTO;
    }

    @Override
    public UserInfoDTO verifyCodeLogin(VerifyCodeParam param) throws Exception {
        // 判断验证码是否正确
        String code = stringRedisTemplate.opsForValue().get(RedisKey.LOGIN_USER_CODE_KEY(param.getMobile()));
        System.out.println(code+"111");
        if (code == null) {
            throw new Exception("验证码已过期");
        }
        if (!code.equals(String.valueOf(param.getVerifyCode()))){
            throw new Exception("验证码错误");
        }

        System.out.println("Redis验证码: " + code);
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", param.getMobile());
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);

        if (userInfo == null) {
            throw new Exception("用户未注册");
        }
        UserInfoDTO userInfoDTO = BeanUtil.toBean(userInfo, UserInfoDTO.class);
        return userInfoDTO;
    }

    @Override
    public void sendLoginVerifyCode(String mobile) throws Exception {
        //检查验证码有效期
        if (stringRedisTemplate.hasKey(RedisKey.LOGIN_USER_CODE_STATE(mobile) + mobile)) {
            throw new Exception("验证码发送频繁，请稍后再试");
        }
        //去重
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile);
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if (userInfo == null) {
            throw new Exception("手机号不存在");
        }
        //调用第三方API发送短信验证码
        Integer loginCode = smsUtil.sendCode(mobile);
        System.out.println(loginCode+"222");
        //保存验证码到redis
        stringRedisTemplate.opsForValue().set(RedisKey.LOGIN_USER_CODE_KEY(mobile), loginCode+"", 10 * 60, TimeUnit.SECONDS);

    }

    @Override
    public void checkOldPassword(Integer userId, String oldPassword) throws Exception {
        UserInfo userInfo = userInfoMapper.selectById(userId);
        if (userInfo == null) {
            throw new Exception("用户不存在");
        }
        if (!MD5Util.md5(oldPassword, userInfo.getMobile()).equals(userInfo.getPassword())) {
            throw new Exception("旧密码错误");
        }
    }

    @Override
    public void sendRegisterVerifyCode(String mobile) throws Exception {
        //检查验证码有效期
        if (stringRedisTemplate.hasKey(RedisKey.REGISTER_USER_CODE_STATE(mobile) + mobile)) {
            throw new Exception("验证码发送频繁，请稍后再试");
        }
        //去重
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile);
        UserInfo userInfo = userInfoMapper.selectOne(queryWrapper);
        if (userInfo != null) {
            throw new Exception("手机号已注册");
        }
        //调用第三方API发送短信验证码
        Integer registerCode = smsUtil.sendCode(mobile);
        //保存验证码到redis
        stringRedisTemplate.opsForValue().set(RedisKey.REGISTER_USER_CODE_KEY(mobile), registerCode.toString(), 10 * 60);


    }

    @Override
    public void updatePoint(UpdatePointParam param) throws Exception {
        // 校验用户是否存在
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo == null) {
            throw new Exception("用户不存在");
        }

        // 如果积分变化数为负数，校验积分是否足够
        if (param.getPointChangeNum() < 0) {
            // 校验积分是否足够
            if (Math.abs(param.getPointChangeNum()) > userInfo.getPoint()) {
                throw new Exception("积分不足");
            }
        }

        // 更新用户积分
        userInfo.setPoint(userInfo.getPoint() + param.getPointChangeNum());
        userInfoMapper.updateById(userInfo);
        //新增积分日志变动
        PointsLog pointsLog = new PointsLog();
        pointsLog.setPointChangeNum(param.getPointChangeNum());
        pointsLog.setUserId(param.getUserId());
        pointsLog.setUpdateTime(LocalDateTime.now());

        if(param.getPointChangeNum()<0){
            pointsLog.setPointChange("减少");
        }else{
            pointsLog.setPointChange("增加");
        }

        pointsLogService.addPointsLog(pointsLog);



    }

    @Override
    public void selectAddress(SelectAddressParam param) throws Exception {
        // 根据 userId 查询用户信息
        UserInfo userInfo = userInfoMapper.selectById(param.getUserId());
        if (userInfo == null) {
            throw new Exception("用户不存在");
        }

        // 更新用户的经度、纬度和地址
        userInfo.setLocalLongitude(param.getLocalLongitude());
        userInfo.setLocalLatitude(param.getLocalLatitude());
        userInfo.setLocalAddress(param.getLocalAddress());

        // 保存更新的用户信息
        userInfoMapper.updateById(userInfo);
    }


}
